﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Web;
using CommerceOne.Common;
using CommerceOne.Domains.Commons;
using CommerceOne.Domains.Entities;
using CommerceOne.Domains.Repositories;
using CommerceOne.Domains.SqlRepositories;

namespace CommerceOne.Widgets.FilterNavigation
{
    public class NavigationFilterController
    {
        private const string QUERY = "filter";
        private readonly IBrandRepository brandRepository = new SqlBrandRepository();
        private readonly ICategoryRepository categoryRepository = new SqlCategoryRepository();
        private List<NavigationSelectedItem> selectedItem = new List<NavigationSelectedItem>();

        public SearchProductResult SearchResult { get; set; }
        public string FilterStr { get; set; }

        private string pageType = string.Empty;
        private int objectId;

        /// <summary>
        /// Initializes a new instance of the <see cref="NavigationFilterController"/> class.
        /// </summary>
        public NavigationFilterController()
        {
            this.FilterStr = System.Web.HttpContext.Current.Request.QueryString[QUERY];
        }

        /// <summary>
        /// Makes the search param.
        /// </summary>
        /// <returns></returns>
        public List<IFilterParam> MakeSearchParam()
        {
            List<IFilterParam> filterParams = new List<IFilterParam>();

            if (string.IsNullOrEmpty(this.FilterStr)) return filterParams;

            string[] param = this.FilterStr.Split(new char[] {'$'}, StringSplitOptions.RemoveEmptyEntries);
            foreach (string str in param)
            {
                string[] paramSplit = str.Split(new char[] {':'}, StringSplitOptions.RemoveEmptyEntries);
                if (paramSplit.Count() != 2) continue;
                
                NavigationSelectedItem item = new NavigationSelectedItem(paramSplit[0], paramSplit[1]);
                filterParams.AddRange(item.MakeFilterParam());
                this.selectedItem.Add(item);
            }
            return filterParams;
        }

        /// <summary>
        /// Gets the view model.
        /// </summary>
        /// <param name="pageType">Type of the page.</param>
        /// <returns></returns>
        public NavigationFilterViewModel GetViewModel(string pageType, int objectId)
        {
            this.pageType = pageType;
            this.objectId = objectId;
            NavigationFilterViewModel viewModel = new NavigationFilterViewModel();
            viewModel.BrandViewModel = MakeBrandViewModel();
            viewModel.CategoryViewModel = MakeDepartmentViewModel();
            viewModel.PriceViewModel = MakePriceViewModel();
            return viewModel;
        }

        /// <summary>
        /// Makes the price view model.
        /// </summary>
        /// <returns></returns>
        public NavigationFilterModelItem MakePriceViewModel()
        {
            decimal priceStep = 1500000;
            decimal minPrice = this.SearchResult.MinPrice.HasValue ?  this.SearchResult.MinPrice.Value : 0;
            decimal maxPrice = this.SearchResult.MaxPrice.HasValue ? this.SearchResult.MaxPrice.Value : 0;

            List<PriceItem> pricesItem = new List<PriceItem>();
            int minRullt = (int)Math.Ceiling(minPrice / priceStep);
            int maxResult = (int)Math.Floor(maxPrice / priceStep);

            PriceItem priceItemMin = new PriceItem(minPrice, minRullt*priceStep);
            priceItemMin.Total = this.SearchResult.ResultItem.Where(p => (p.EnablePrice2 ? p.Price2 : p.Price1) < priceItemMin.Max).Count();
            pricesItem.Add(priceItemMin);

            int previousStep = 0;
            for (int i = minRullt; i < maxResult - 1; i++)
            {
                PriceItem prItem = new PriceItem(i * priceStep, (i + 1) * priceStep);
                prItem.Total = this.SearchResult.ResultItem.Where(p => (p.EnablePrice2 ? p.Price2 : p.Price1) >= prItem.Min && (p.EnablePrice2 ? p.Price2 : p.Price1) < prItem.Max).Count();
                if (prItem.Total == 0) 
                { 
                    if (previousStep ==0 ) previousStep = i;
                    continue;
                }
                if (previousStep != 0)
                {
                    prItem.Min = previousStep*priceStep;
                    previousStep = 0;
                }
                //prItem.Total = 
                pricesItem.Add(prItem);
            }

            PriceItem priceItemMax = new PriceItem(maxResult*priceStep, maxPrice);
            priceItemMax.Total = this.SearchResult.ResultItem.Where(p => (p.EnablePrice2 ? p.Price2 : p.Price1) >= priceItemMax.Min).Count();
            pricesItem.Add(priceItemMax);

            // Get viewModel
            NavigationFilterModelItem viewModel = new NavigationFilterModelItem();
            NavigationSelectedItem priceSelectedItem = this.selectedItem.Where(p => p.ItemType == FilterItem.Price).FirstOrDefault();

            if (priceSelectedItem != null)
            {
                NavigationFilterItem selectedFilterItem = new NavigationFilterItem();
                if (priceSelectedItem.Value == null || priceSelectedItem.Value.Count != 2) throw  new Exception("Custom error: Price parameter is not valid");
                decimal price1 = Convert.ToDecimal(priceSelectedItem.Value[0]);
                decimal price2 = Convert.ToDecimal(priceSelectedItem.Value[1]);

                if (price2 >= this.SearchResult.MaxPrice)
                {
                    selectedFilterItem.ItemCount = this.SearchResult.ResultItem.Where(p => (p.EnablePrice2 ? p.Price2 : p.Price1) >= price1).Count(); ;
                    selectedFilterItem.ItemName = string.Format("Giá từ {0} đến dưới {1}", price1, price2);
                }
                else
                {
                    selectedFilterItem.ItemCount = this.SearchResult.ResultItem.Where(p => (p.EnablePrice2 ? p.Price2 : p.Price1) >= price1 && (p.EnablePrice2 ? p.Price2 : p.Price1) < price2).Count(); ;
                    selectedFilterItem.ItemName = string.Format("Giá từ {0} đến dưới {1}", price1, price2);
                }
                
                selectedFilterItem.ItemLink = string.Empty;
                viewModel.FilterItems.Add(selectedFilterItem);

                NavigationFilterItem removedItem = new NavigationFilterItem();
                string query = MakeAntiFilterQueryString(FilterItem.Price);
                query = MakeLink(query);
                removedItem.ItemLink = UrlBuilderService.Instance.GetUrlRoute(this.pageType, this.objectId, 1, string.Empty, query);
                removedItem.ItemName = "x";
                viewModel.RemoveFilterItems = removedItem;

                return viewModel;
            }

            foreach (PriceItem priceItem in pricesItem)
            {
                NavigationFilterItem item = new NavigationFilterItem();
                item.ItemCount = priceItem.Total;
                item.ItemName = string.Format("Từ {0} đến {1}", priceItem.Min, priceItem.Max);
                string query = MakeFilterQueryString(FilterItem.Price, priceItem.Min, priceItem.Max);
                query = MakeLink(query);
                item.ItemLink = "http://localhost:50046/" + UrlBuilderService.Instance.GetUrlRoute(this.pageType, this.objectId, 1, string.Empty, query);
                viewModel.FilterItems.Add(item);
            }
            return viewModel;

            return null;
        }

        /// <summary>
        /// Makes the brand view model.
        /// </summary>
        /// <returns></returns>
        public NavigationFilterModelItem MakeBrandViewModel()
        {
            NavigationFilterModelItem viewModel = new NavigationFilterModelItem();

            NavigationSelectedItem selectedItem = this.selectedItem.Where(p => p.ItemType == FilterItem.Brand).FirstOrDefault();
            if (selectedItem != null)
            {
                int brandId = Convert.ToInt32(selectedItem.Value[0]);
                Brand selectedBrand = this.brandRepository.GetById(brandId);
                if (selectedBrand == null) return viewModel;
                NavigationFilterItem selectedFilterItem = new NavigationFilterItem();
                selectedFilterItem.ItemCount = this.SearchResult.ResultItem.Where(p => p.BrandId == brandId).Count(); ;
                selectedFilterItem.ItemName = selectedBrand.Name;
                selectedFilterItem.ItemLink = string.Empty;
                viewModel.FilterItems.Add(selectedFilterItem);

                NavigationFilterItem removedItem = new NavigationFilterItem();
                string query = MakeAntiFilterQueryString(FilterItem.Brand);
                query = MakeLink(query);
                removedItem.ItemLink = UrlBuilderService.Instance.GetUrlRoute(this.pageType, this.objectId, 1, string.Empty, query);
                removedItem.ItemName = "x";
                viewModel.RemoveFilterItems = removedItem;

                return viewModel;
            }

            List<Brand> brands = this.brandRepository.GetAll();
            foreach (Brand brand in brands)
            {
                int counting = this.SearchResult.ResultItem.Where(p => p.BrandId == brand.Id).Count();
                if (counting == 0) continue;
                NavigationFilterItem item = new NavigationFilterItem();
                item.ItemCount = counting;
                item.ItemName = brand.Name;
                string query = MakeFilterQueryString(FilterItem.Brand, brand.Id);
                query = MakeLink(query);
                item.ItemLink = "http://localhost:50046/" + UrlBuilderService.Instance.GetUrlRoute(this.pageType, this.objectId, 1, string.Empty, query);
                viewModel.FilterItems.Add(item);
            }
            return viewModel;
        }

        /// <summary>
        /// Makes the department view model.
        /// </summary>
        /// <returns></returns>
        public NavigationFilterModelItem MakeDepartmentViewModel()
        {
            NavigationFilterModelItem viewModel = new NavigationFilterModelItem();

            NavigationSelectedItem selectedItem = this.selectedItem.Where(p => p.ItemType == FilterItem.Category).FirstOrDefault();
            if (selectedItem != null)
            {
                int brandId = Convert.ToInt32(selectedItem.Value[0]);
                Category selectedBrand = this.categoryRepository.GetById((brandId));
                if (selectedBrand == null) return viewModel;
                NavigationFilterItem selectedFilterItem = new NavigationFilterItem();
                selectedFilterItem.ItemCount = this.SearchResult.ResultItem.Where(p => p.CategoryId == brandId).Count(); ;
                selectedFilterItem.ItemName = selectedBrand.Name;
                selectedFilterItem.ItemLink = string.Empty;
                viewModel.FilterItems.Add(selectedFilterItem);

                NavigationFilterItem removedItem = new NavigationFilterItem();
                string query = MakeAntiFilterQueryString(FilterItem.Category);
                query = MakeLink(query);
                removedItem.ItemLink = UrlBuilderService.Instance.GetUrlRoute(this.pageType, this.objectId, 1, string.Empty, query);
                removedItem.ItemName = "x";
                viewModel.RemoveFilterItems = removedItem;

                return viewModel;
            }

            List<Category> brands = this.categoryRepository.GetAll();
            foreach (Category brand in brands)
            {
                int counting = this.SearchResult.ResultItem.Where(p => p.CategoryId == brand.Id).Count();
                if (counting == 0) continue;
                NavigationFilterItem item = new NavigationFilterItem();
                item.ItemCount = counting;
                item.ItemName = brand.Name;
                string query = MakeFilterQueryString(FilterItem.Category, brand.Id);
                query = MakeLink(query);
                item.ItemLink = "http://localhost:50046/" + UrlBuilderService.Instance.GetUrlRoute(this.pageType, this.objectId, 1, string.Empty, query);
                viewModel.FilterItems.Add(item);
            }
            return viewModel;
        }

        public string MakeLink(string filterString)
        {
            List<string> queryString = new List<string>();
            foreach (string key in System.Web.HttpContext.Current.Request.QueryString.AllKeys)
            {
                if (QUERY.Equals(key, StringComparison.OrdinalIgnoreCase)) continue;
                queryString.Add(key + "=" + System.Web.HttpContext.Current.Request.QueryString[key]);
            }
             if (!string.IsNullOrEmpty(filterString)) queryString.Add(filterString);
             return string.Join("&", queryString);
        }

        /// <summary>
        /// Makes the filter query string.
        /// </summary>
        /// <param name="item">The item.</param>
        /// <param name="param">The param.</param>
        /// <returns></returns>
        public string MakeFilterQueryString(FilterItem item, params object [] param)
        {
            string queryString = NavigationSelectedItem.MakeQueryString(item, param);
            foreach (var existedItem in selectedItem)
            {
                if (existedItem.ItemType == item) continue;
                string query = existedItem.ReMakeQueryString();
                if (string.IsNullOrEmpty(query)) continue;
                if (!string.IsNullOrEmpty(queryString)) queryString += "$";
                queryString += query;
            }
            if (!string.IsNullOrEmpty(queryString)) queryString = QUERY + "=" + queryString;
            return queryString;
        }

        public string MakeAntiFilterQueryString(FilterItem item)
        {
            string queryString = string.Empty;
            foreach (var existedItem in selectedItem)
            {
                if (existedItem.ItemType == item) continue;
                string query = existedItem.ReMakeQueryString();
                if (string.IsNullOrEmpty(query)) continue;
                if (!string.IsNullOrEmpty(queryString)) queryString += "$";
                queryString += query;
            }
            if (!string.IsNullOrEmpty(queryString)) queryString = QUERY + "=" + queryString;
            return queryString;
        }
        
    }
}